package com.lcredu.seckill.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lcredu.seckill.mapper.SeckillOrderMapper;
import com.lcredu.seckill.pojo.Order;
import com.lcredu.seckill.pojo.SeckillGoods;
import com.lcredu.seckill.pojo.SeckillOrder;
import com.lcredu.seckill.pojo.User;
import com.lcredu.seckill.service.GoodsService;
import com.lcredu.seckill.service.OrderService;
import com.lcredu.seckill.mapper.OrderMapper;
import com.lcredu.seckill.service.SeckillGoodsService;
import com.lcredu.seckill.util.MD5Util;
import com.lcredu.seckill.util.UUIDUtil;
import com.lcredu.seckill.vo.GoodsVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.TimeUnit;

/**
 * @author 18442
 * @description 针对表【t_order(订单主表)】的数据库操作Service实现
 * @createDate 2025-08-28 17:34:22
 */
@Service
@Slf4j
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order>
        implements OrderService {

    @Resource
    private SeckillGoodsService seckillGoodsService;

    @Resource
    private OrderMapper orderMapper;

    @Resource
    private SeckillOrderMapper seckillOrderMapper;


    @Resource
    private RedisTemplate redisTemplate;

//    @Override
//    public Order seckill(User user, GoodsVo goodsVo) {
//        //这里主要做两件事
//        //1.记录订单表
//        //2.记录秒杀订单表
//        //3.秒杀商品库存减一
//        SeckillGoods seckillGoods = seckillGoodsService.getOne(new QueryWrapper<SeckillGoods>().eq("stock_count", goodsVo.getStockCount()));
//        //todo 使用自带的方法看行不行
//        seckillGoods.setStockCount(seckillGoods.getStockCount() - 1);
//        seckillGoodsService.updateById(seckillGoods);
//        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
//        //生成订单表
//        Order order = Order.builder()
//                .userId(goodsVo.getId())
//                .goodsId(goodsVo.getId())
//                .deliveryAddrId(1L)
//                .goodsName(goodsVo.getGoodsName())
//                .goodsCount(goodsVo.getStockCount())
//                .goodsPrice(goodsVo.getSeckillPrice())
//                .orderChannel(1)
//                .status(0)
//                .createDate(LocalDateTime.now()).build();
//
//
//        orderMapper.insert(order);
//        log.info("增加的普通订单表={}", order);
//        //生成秒杀订单表
//        SeckillOrder seckillOrder = new SeckillOrder();
//        seckillOrder.setOrderId(order.getId());
//        seckillOrder.setUserId(user.getId());
//        seckillOrder.setGoodsId(goodsVo.getId());
//        seckillOrderMapper.insert(seckillOrder);
//        log.info("增加的秒杀订单表={}", seckillOrder);
//        return order;
//    }


    /*
        1.优化秒杀
        2.使用mysql的行锁优化下单方案
        3.将订单生成存入redis
     */
    @Transactional
    @Override
    public Order seckill(User user, GoodsVo goodsVo) {
        //这里主要做两件事
        //1.记录订单表
        //2.记录秒杀订单表
        //3.秒杀商品库存减一
        SeckillGoods seckillGoods = seckillGoodsService.getOne(new QueryWrapper<SeckillGoods>().eq("goods_id", goodsVo.getId()));
        //todo 使用自带的方法看行不行
//        seckillGoods.setStockCount(seckillGoods.getStockCount() - 1);
//        seckillGoodsService.updateById(seckillGoods);

        boolean update = seckillGoodsService.update(new UpdateWrapper<SeckillGoods>().setSql("stock_count = stock_count - 1")
                .eq("goods_id", goodsVo.getId()).gt("stock_count", 0));

        //防止订单继续生成,及时返回
        if (!update) {
            return null;
        }

        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        //生成订单表
        Order order = Order.builder()
                .userId(user.getId())
                .goodsId(goodsVo.getId())
                .deliveryAddrId(1L)
                .goodsName(goodsVo.getGoodsName())
                .goodsCount(1)
                .goodsPrice(goodsVo.getSeckillPrice())
                .orderChannel(1)
                .status(0)
                .createDate(LocalDateTime.now()).build();


        orderMapper.insert(order);
        log.info("增加的普通订单表={}", order);
        //生成秒杀订单表
        SeckillOrder seckillOrder = new SeckillOrder();
        seckillOrder.setOrderId(order.getId());
        seckillOrder.setUserId(user.getId());
        seckillOrder.setGoodsId(goodsVo.getId());
        log.info("seckillOrder={}", seckillOrder);

        seckillOrderMapper.insert(seckillOrder);
        log.info("增加的秒杀订单表={}", seckillOrder);

        //将订单存入redis中(order:userId:goodsID)
        // 获取Redis的值操作对象，用于执行基本的键值对操作
        ValueOperations valueOperations = redisTemplate.opsForValue();
        // 将秒杀订单信息存储到Redis中，键为"order:用户ID:商品ID"的格式，值为秒杀订单对象
        valueOperations.set("order:" + user.getId() + ":" + goodsVo.getId(), seckillOrder);

        return order;
    }

    /*
        1.生成地址(seckillPath:userId:goodsId)
        2.将地址放入redis
     */
    @Override
    public String createPath(User user, Long goodsId) {
        if (user == null || goodsId < 0) {
            return null;
        }
        String string = MD5Util.MD5(UUIDUtil.getUUID());

        String path = "seckillPath:" + user.getId() + ":" + goodsId;

        redisTemplate.opsForValue().set(path, string, 60, TimeUnit.SECONDS);

        return string;
    }

    /*
        1.判空
        2.去redis中查找
     */
    @Override
    public boolean checkPath(User user, Long goodsId, String path) {
        if (user == null || goodsId < 0 || !StringUtils.hasText(path)) {
            return false;
        }
        String redisPath = (String) redisTemplate.opsForValue().get("seckillPath:" + user.getId() + ":" + goodsId);

        return path.equals(redisPath);
    }

    @Override
    public boolean checkCaptcha(User user, Long goodsId, String captcha) {
        if (user == null || goodsId < 0 || !StringUtils.hasText(captcha)) {
            return false;
        }
        String redisCaptcha = (String) redisTemplate.opsForValue().get("captcha:" + user.getId() + ":" + goodsId);
        return captcha.equals(redisCaptcha);
    }
}




